package top.defaults.colorpicker;


import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.StackLayout;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;
import top.defaults.colorpicker.util.NumCalcUtil;

import static top.defaults.colorpicker.Constants.SELECTOR_RADIUS_DP;

/**
 * ColorWheelSelector
 *
 * @author: jjy
 * @since 2021-04-16
 */
public class ColorWheelView extends StackLayout implements Component.TouchEventListener,
    Component.EstimateSizeListener {
    private double radius;
    private double centerX;
    private double centerY;
    private double selectorRadiusPx = SELECTOR_RADIUS_DP * 3;
    private Point currentPoint = new Point();
    private int currentColor = Color.MAGENTA.getValue();
    private ColorWheelSelector selector;
    private int netHeight;
    private ColorWheelPalette palette;
    private float[] currentHSV;
    ColorChangeListener mColorChangeListener;

    public void setColorChangeListener(ColorChangeListener colorChangeListener) {
        this.mColorChangeListener = colorChangeListener;
    }

    public ColorWheelView(Context context, boolean isDialog) {
        this(context, null);
        initView(context);
    }

    public ColorWheelView(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    public ColorWheelView(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    private void initView(Context context) {
        this.setEstimateSizeListener(this::onEstimateSize);
        this.setTouchEventListener(this::onTouchEvent);
        currentHSV = new float[3];
        selectorRadiusPx = Utils.dip2px(context, SELECTOR_RADIUS_DP);
        {
            LayoutConfig layoutParams = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                    ComponentContainer.LayoutConfig.MATCH_CONTENT);
            palette = new ColorWheelPalette(context);
            int padding = (int) selectorRadiusPx;
            palette.setPadding(padding, padding, padding, padding);
            addComponent(palette, layoutParams);
        }
        {
            LayoutConfig layoutParams = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                    ComponentContainer.LayoutConfig.MATCH_CONTENT);
            selector = new ColorWheelSelector(context);
            selector.setSelectorRadiusPx((float) selectorRadiusPx);
            addComponent(selector, layoutParams);
        }
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int maxWidth = EstimateSpec.getSize(widthMeasureSpec);
        int maxHeight = EstimateSpec.getSize(heightMeasureSpec);
        int width, height;
        width = height = Math.min(maxWidth, maxHeight);
        onSizeChanged(width, height);
        return false;
    }

    protected void onSizeChanged(int w, int h) {
        System.out.println("width" + w +  "getMarginTop: " + getMarginTop());
        int netWidth = w - getMarginLeft() - getMarginRight();
        netHeight = h - getMarginTop() - getMarginBottom();
        radius = Math.min(netWidth, netHeight) * 0.5f - selectorRadiusPx;
        if (radius < 0) return;
        centerX = netWidth * 0.5f;
        centerY = netHeight * 0.5f;
        setColor(currentColor, false);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {

        float x = getTouchX(event, event.getIndex(), component);
        float y = getTouchY(event, event.getIndex(), component);

        if(event.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
            double r = Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY));
            if (r > radius) return false;
        }
        update(x, y);
        return true;
    }

    public void update(float x, float y) {

        int color = getColorAtPoint(x, y);
        updateSelector(x, y);
        mColorChangeListener.onColorChange(color);
    }

    private float getTouchX(TouchEvent touchEvent, int index, Component component) {
        float touchX = 0;
        if (touchEvent.getPointerCount() > index) {
            int[] xy = component.getLocationOnScreen();
            if (xy != null && xy.length == 2) {
                touchX = NumCalcUtil.subtract(touchEvent.getPointerPosition(index).getX(), xy[0]);
            } else {
                touchX = touchEvent.getPointerPosition(index).getX();
            }
        }
        return touchX;
    }

    private float getTouchY(TouchEvent touchEvent, int index, Component component) {
        float touchY = 0;
        if (touchEvent.getPointerCount() > index) {
            int[] xy = component.getLocationOnScreen();
            if (xy != null && xy.length == 2) {
                touchY = NumCalcUtil.subtract(touchEvent.getPointerPosition(index).getY(), xy[1]);
            } else {
                touchY = touchEvent.getPointerPosition(index).getY();
            }
        }
        return touchY;
    }

    public int getCurrentColor(){
        return getColorAtPoint(currentPoint.getPointX(), currentPoint.getPointY());
    }

    public float[] getCurrentHSV(){
        return currentHSV.clone();
    }
    private int getColorAtPoint(float eventX, float eventY) {
        double x = eventX - centerX;
        double y = eventY - centerY;
        double r = Math.sqrt(x * x + y * y);
        float[] hsv = {0, 0, 0};
        hsv[0] = (float) (((Math.atan2(y, -x) / Math.PI * 180f) + 180)/360);
        hsv[1] = Math.max(0f, Math.min(1f, (float) (r / radius)));
        currentHSV = hsv;
        int colors[] = ColorConverUtils.hsvToRgb(hsv[0], hsv[1], 1);
        int color = Color.rgb((int)colors[0], (int)colors[1], (int)colors[2]);
        return color;
    }

    public void setColor(int color, boolean shouldPropagate) {
        int[] ints = ColorConverUtils.colorToRgb(color);
        double[] hsvColor = ColorConverUtils.rgbToHsv(ints[0], ints[1], ints[2]);
        Color.rgb((int)hsvColor[0], (int)hsvColor[1], (int)hsvColor[2]);
        hsvColor[0] = (float) hsvColor[0];
        hsvColor[1] = (float) hsvColor[1];
        hsvColor[2] = (float) hsvColor[2];
        float r = (float) hsvColor[1] * (float) radius;
        float radian = (float) (hsvColor[0] / 180f * Math.PI);
        updateSelector((float) (r * Math.cos(radian) + centerX), (float) (-r * Math.sin(radian) + centerY));
        currentColor = color;
    }
    private void updateSelector(float eventX, float eventY) {
        double x = eventX - centerX;
        double  y = eventY - centerY;
        double r = Math.sqrt(x * x + y * y);
        if (r > radius) {
            x *= radius / r;
            y *= radius / r;
        }
        currentPoint.modify((float)(x + centerX),  (float)(y + centerY));
        selector.setCurrentPoint(currentPoint);
    }

}
